#pragma once
#include <cinttypes>
#include <cmath>

struct Point{
    int16_t x;
    int16_t y;
    void rnd(uint16_t range_x, uint16_t range_y) {
        this->x = (int16_t)(random() % range_x);
        this->y = (int16_t)(random() % range_y);
    }
    void random_inc() {
        switch (random() % 4) {
            case 0: x--; break;
            case 1: x++; break;
            case 2: y--; break;
            case 3: y++; break;
        }
    }
    Point(int16_t x, int16_t y) {
        this->x = x;
        this->y = y;
    }
};

struct ListItem {
    Point point;
    ListItem * tail{};
    void * data;

    explicit ListItem(Point p) : point(p.x, p.y) {
        this->data = nullptr;
    }
};

class OneDirectionList {
private:
protected:
    ListItem * head = nullptr;
public:
    explicit OneDirectionList() {
        this->head = nullptr;
    }

    ~OneDirectionList() {
        this->release();
    }


    ListItem * getHead() {
        return this->head;
    }

    void release() {
        if (this->head != nullptr) {
            ListItem *current = this->head;
            do {
                ListItem *next = current->tail;
                delete current;
                current = next;
            } while (this->head != current);
            this->head = nullptr;
        }
    }

    void add_head(ListItem * item) {
        this->add_tail(item);
        this->head = item;
    }

    void add_tail(ListItem * item) {
        if (head == nullptr) {
            head = item;
            head->tail = head;
        } else {
            item->tail = this->head->tail;
            this->head->tail = item;
        }
    }

    ListItem * find(Point point) {
        if (this->head != nullptr) {
            ListItem *current = head;
            do {
                if ((current->point.x == point.x) && (current->point.y == point.y))
                    return current;
                current = current->tail;
            } while (head != current);
        }
        return nullptr;
    }

};
